package cn.slipi.admin.biz;

import cn.slipi.admin.biz.vo.admin.AdminLogVo;
import cn.slipi.admin.biz.vo.admin.AdminVo;
import cn.slipi.admin.biz.vo.admin.TokenVo;
import cn.slipi.admin.common.dto.PageDTO;
import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.utils.DateUtil;
import cn.slipi.admin.common.utils.EncryptUtil;
import cn.slipi.admin.common.utils.ImgAuthCode;
import cn.slipi.admin.common.utils.cache.redis.RedisClient;
import cn.slipi.admin.common.utils.dozer.impl.ConvertBean;
import cn.slipi.admin.constants.AdminConstants;
import cn.slipi.admin.common.contants.enumtype.AdminLogType;
import cn.slipi.admin.constants.properties.AccountProperties;
import cn.slipi.admin.context.dto.Menu;
import cn.slipi.admin.context.dto.PermissionInfo;
import cn.slipi.admin.context.dto.VisitorInfo;
import cn.slipi.admin.controller.form.admin.*;
import cn.slipi.admin.entity.TSysAdmin;
import cn.slipi.admin.entity.TSysAdminLog;
import cn.slipi.admin.entity.TSysMenu;
import cn.slipi.admin.service.TSysAdminService;
import cn.slipi.admin.service.TSysPermissionService;
import cn.slipi.admin.service.dto.in.m.*;
import cn.slipi.admin.service.dto.out.AdminOutDTO;
import cn.slipi.admin.service.dto.out.PermissionDTO;
import cn.slipi.admin.task.LogTask;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 用户业务层
 */
@Component
public class AdminBiz {

    private final static Logger LOG = LoggerFactory.getLogger(AdminBiz.class);

    @Autowired
    private LogTask logTask;

    @Autowired
    private ConvertBean convertBean;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private TSysAdminService sysAdminService;

    @Autowired
    private AccountProperties accountProperties;

    @Autowired
    private TSysPermissionService sysPermissionService;

    public Boolean initPassword(Integer id) {
        return this.sysAdminService.initPassword(id);
    }


    public Boolean updateAdmin(Integer userId, AdminUpdateForm userUpdateForm) {
        AdminUpdateDTO userUpdateDTO = this.convertBean.convert(userUpdateForm, AdminUpdateDTO.class);
        return this.sysAdminService.updateAdmin(userId, userUpdateDTO);
    }

    public Boolean changePassword(Integer userId, ChangePasswordForm changePasswordForm) {
        ChangePasswordDTO changePasswordDTO = this.convertBean.convert(changePasswordForm, ChangePasswordDTO.class);
        return this.sysAdminService.changePassword(userId, changePasswordDTO);
    }

    public Integer addAdmin(AdminCreateForm userCreateForm) {
        AdminCreateDTO userCreateDTO = this.convertBean.convert(userCreateForm, AdminCreateDTO.class);
        //管理员初始密码
        userCreateDTO.setPassword(AdminConstants.INIT_PASSWORD);
        return this.sysAdminService.addAdmin(userCreateDTO);
    }

    public PageDTO<AdminVo> getAdminList(AdminQueryForm userQueryForm) {
        AdminQueryDTO userQueryDTO = this.convertBean.convert(userQueryForm, AdminQueryDTO.class);
        PageDTO<AdminOutDTO> page = this.sysAdminService.getAdminList(userQueryDTO);
        return PageDTO.of(page, user -> this.convertBean.convert(user, AdminVo.class));
    }

    public Boolean checkImageCode(String code) {
        String key = AccountProperties.REDIS_KEY_IMG_AUTH_CODE + ":{" + code + "}";
        LOG.info("生成图片验证码KEY:{},FIELD:{}", key, code);
        if (this.redisClient.hHasKey(key, code)) {
            String redisCode = this.redisClient.hGet(key, code, String.class);
            if (code.toUpperCase().equals(redisCode)) {
                return true;
            } else {
                throw new BizException(10000, "img.auth.code.illegal");
            }
        } else {
            throw new BizException(10000, "img.auth.code.illegal");
        }
    }

    public ImgAuthCode getImgAuthCode() {
        ImgAuthCode authCode = new ImgAuthCode(accountProperties.authCodeImgWidth, accountProperties.authCodeImgHeight,
                accountProperties.codeCountInImg, accountProperties.lineCountInImg);
        String key = AccountProperties.REDIS_KEY_IMG_AUTH_CODE + ":{" + authCode.getCode() + "}";
        this.redisClient.hSet(key, authCode.getCode(), authCode.getCode());
        LOG.info("生成图片验证码KEY:{},FIELD:{},VALUE:{}", key, authCode.getCode(), authCode.getCode());
        this.redisClient.expire(key, accountProperties.imgCodeExpireTime);
        return authCode;
    }

    public AdminVo getDetail(Long id) {
        AdminDTO userDTO = this.sysAdminService.getDetail(id);
        return this.convertBean.convert(userDTO, AdminVo.class);
    }


    public TokenVo getToken(GetTokenForm getTokenForm) {
        CheckAdminDTO checkAdminDTO = this.convertBean.convert(getTokenForm, CheckAdminDTO.class);
        TSysAdmin user = this.sysAdminService.checkAdmin(checkAdminDTO);
        if (null == user) {
            throw new BizException(10000, "name.password.err");
        }
        if (user.getCheck().equals(AdminConstants.USER_UNCHECK)) {
            throw new BizException(10000, "user.forb.call");
        }
        //生成token
        String token = EncryptUtil.getMD5(user.getId() + "_" + user.getLastLoginTime());
        if (null != this.redisClient.get(token, VisitorInfo.class)) {
            //已经登陆
            this.redisClient.deleteByKey(token);
        }
        //没有登陆
        Long time = DateUtil.getTimeByMinSecond();
        token = EncryptUtil.getMD5(user.getId() + "_" + time);
        LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
        loginInfoDTO.setLastLoginTime(time);
        if (this.sysAdminService.updateLoginInfo(user, loginInfoDTO)) {
            //根据用户id获取权限
            VisitorInfo visitorInfo = getVisitorInfo(user);
            this.redisClient.set(token, visitorInfo, AdminConstants.TOKEN_LIFE);
            TokenVo tokenVo = this.convertBean.convert(visitorInfo, TokenVo.class);
            tokenVo.setToken(token);
            //记录登陆日志
            this.logTask.writeLog(user.getId(), AdminLogType.LOGIN.getValue(), "用户登陆", "登陆成功!");
            //返回结果
            return tokenVo;
        } else {
            throw new BizException(10000, "login.info.fail");
        }
    }

    private VisitorInfo getVisitorInfo(TSysAdmin user) {
        VisitorInfo visitorInfo = new VisitorInfo();
        this.convertBean.convert(user, visitorInfo);
        List<PermissionDTO> permissionList = this.sysPermissionService.getPermissionByAdminId(user.getId());
        if (permissionList.size() > 0) {
            List<PermissionInfo> permissionInfoDTOList = this.convertBean.convert(permissionList, PermissionInfo.class);
            visitorInfo.setPermissions(permissionInfoDTOList);
        }
        List<TSysMenu> menuList = this.sysPermissionService.getMenuByAdminId(user.getId());
        if (menuList.size() > 0) {
            List<Menu> menuDTOList = this.convertBean.convert(menuList, Menu.class);
            visitorInfo.setMenus(menuDTOList);
        }
        return visitorInfo;
    }

    public PageDTO<AdminLogVo> getList(AdminLogQueryForm userLogQueryForm) {
        AdminLogQueryDTO userLogQueryDTO = this.convertBean.convert(userLogQueryForm, AdminLogQueryDTO.class);
        IPage<TSysAdminLog> page = this.sysAdminService.getAdminLogList(userLogQueryDTO);
        return PageDTO.of(page, userLog -> this.convertBean.convert(userLog, AdminLogVo.class));
    }

}
